package com.neusoft.hifly.commons.web;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

/**
 * Title: 核心类库
 * <p>
 * Description: IP 白名单
 * <p>
 * Copyright: 2019
 * <p>
 * Company: 东软汉枫
 *
 * @author lh_neu
 * @version 1.0.0
 */
public class IPUtil {
	// 允许所有ip标志位
	public static final String DEFAULT_ALLOW_ALL_FLAG = "*";
	// 禁止所有ip标志位
	public static final String DEFAULT_DENY_ALL_FLAG = "0";
	// IP的正则
	private static Pattern pattern = Pattern
			.compile("(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
					+ "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})");

	/**
	 * 根据IP白名单列表，获取所有IP地址
	 *
	 * @param allowIp
	 *            白名单，例如：[192.168.1.1, 192.168.3.17-192.168.3.38, 192.168.2.0-192.168.2.255]
	 * @return 所有IP地址，例如：[192.168.1.1, 192.168.3.17, 192.168.3.18, ..., 192.168.3.38, 192.168.2.0, 192.168.2.1, ...,
	 *         192.168.2.255]
	 */
	public static List<String> getIpByAllowIp(final String allowIp) {
		if (StringUtils.isEmpty(allowIp)) {
			return null;
		}
		final Set<String> ipList = IPUtil.getAvaliIpList(allowIp);
		if (ipList == null || ipList.isEmpty()) {
			return null;
		}

		final List<String> ips = new ArrayList<String>(0);
		for (String ip : ipList) {
			if (ip.indexOf("-") > 0) {
				// IP段
				String fromIP = ip.split("-")[0];
				final String endIP = ip.split("-")[1];

				final int fromNum = Integer.parseInt(StringUtils.substringAfterLast(fromIP, "."));
				final int endNum = Integer.parseInt(StringUtils.substringAfterLast(endIP, "."));

				fromIP = StringUtils.substringBeforeLast(fromIP, ".");
				for (int i = fromNum; i <= endNum; i++) {
					ip = fromIP + "." + i;
					if (IPUtil.validate(ip)) {
						ips.add(ip);
					}
				}
			} else {
				// 单个IP
				if (IPUtil.validate(ip)) {
					ips.add(ip);
				}
			}
		}
		return ips;
	}

	/**
	 * 根据IP白名单设置获取可用的IP列表
	 *
	 * @param allowIp
	 *            白名单
	 * @return 可用的IP列表
	 */
	public static Set<String> getAvaliIpList(final String allowIp) {
		if (StringUtils.isEmpty(allowIp)) {
			return null;
		}
		final Set<String> ipList = new HashSet<String>(0);
		for (final String allow : allowIp.replaceAll("\\s", "").split(";")) {
			if (allow.indexOf("*") > -1) {
				final String[] ips = allow.split("\\.");
				final String[] from = new String[] { "0", "0", "0", "0" };
				final String[] end = new String[] { "255", "255", "255", "255" };
				List<String> tem = new ArrayList<String>();
				for (int i = 0; i < ips.length; i++) {
					if (ips[i].indexOf("*") > -1) {
						tem = IPUtil.complete(ips[i]);
						from[i] = null;
						end[i] = null;
					} else {
						from[i] = ips[i];
						end[i] = ips[i];
					}
				}

				final StringBuffer fromIP = new StringBuffer();
				final StringBuffer endIP = new StringBuffer();
				for (int i = 0; i < 4; i++) {
					if (from[i] != null) {
						fromIP.append(from[i]).append(".");
						endIP.append(end[i]).append(".");
					} else {
						fromIP.append("[*].");
						endIP.append("[*].");
					}
				}
				fromIP.deleteCharAt(fromIP.length() - 1);
				endIP.deleteCharAt(endIP.length() - 1);

				for (final String s : tem) {
					final String ip = fromIP.toString().replace("[*]", s.split(";")[0]) + "-"
							+ endIP.toString().replace("[*]", s.split(";")[1]);
					if (IPUtil.validate(ip)) {
						ipList.add(ip);
					}
				}
			} else {
				if (IPUtil.validate(allow)) {
					ipList.add(allow);
				}
			}
		}
		return ipList;
	}

	/**
	 * 对单个IP节点进行范围限定
	 *
	 * @param ip
	 *            IP地址
	 * @return 返回限定后的IP范围，格式为List[10;19, 100;199]
	 */
	public static List<String> complete(final String ip) {
		if (StringUtils.isEmpty(ip)) {
			return null;
		}
		final List<String> list = new ArrayList<String>(0);
		if (ip.length() == 1) {
			list.add("0;255");
		} else if (ip.length() == 2) {
			final String s1 = IPUtil.complete(ip, 1);
			if (s1 != null) {
				list.add(s1);
			}
			final String s2 = IPUtil.complete(ip, 2);
			if (s2 != null) {
				list.add(s2);
			}
		} else {
			final String s1 = IPUtil.complete(ip, 1);
			if (s1 != null) {
				list.add(s1);
			}
		}
		return list;
	}

	/**
	 * 拼接IP
	 *
	 * @param ip
	 *            IP地址
	 * @param length
	 *            长度
	 * @return IP地址
	 */
	public static String complete(final String ip, final int length) {
		if (StringUtils.isEmpty(ip)) {
			return "";
		}
		String from = "";
		String end = "";
		if (length == 1) {
			from = ip.replace("*", "0");
			end = ip.replace("*", "9");
		} else {
			from = ip.replace("*", "00");
			end = ip.replace("*", "99");
		}
		if (Integer.valueOf(from) > 255) {
			return null;
		}
		if (Integer.valueOf(end) > 255) {
			end = "255";
		}
		return from + ";" + end;
	}

	/**
	 * 在添加至白名单时进行格式校验
	 *
	 * @param ip
	 *            当前IP
	 * @return 是否正确
	 */
	public static boolean validate(final String ip) {
		if (StringUtils.isEmpty(ip)) {
			return false;
		}
		for (final String s : ip.split("-")) {
			if (!IPUtil.pattern.matcher(s).matches()) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 根据IP,及可用Ip列表来判断ip是否包含在白名单之中
	 *
	 * @param ip
	 *            当前IP
	 * @param ipList
	 *            白名单
	 * @return 是否在白名单中
	 */
	public static boolean checkLoginIP(final String ip, final Set<String> ipList) {
		if (StringUtils.isEmpty(ip)) {
			return false;
		}
		if (ipList.isEmpty() || ipList.contains(ip)) {
			return true;
		} else {
			for (final String allow : ipList) {
				if (allow.indexOf("-") > -1) {
					final String[] from = allow.split("-")[0].split("\\.");
					final String[] end = allow.split("-")[1].split("\\.");
					final String[] tag = ip.split("\\.");

					// 对IP从左到右进行逐段匹配
					boolean check = true;
					for (int i = 0; i < 4; i++) {
						final int s = Integer.valueOf(from[i]);
						final int t = Integer.valueOf(tag[i]);
						final int e = Integer.valueOf(end[i]);
						if (!(s <= t && t <= e)) {
							check = false;
							break;
						}
					}
					if (check) {
						return true;
					}
				}
			}
		}
		return false;
	}

	/**
	 * 根据IP地址，及IP白名单设置规则判断IP是否包含在白名单
	 *
	 * @param ip
	 *            当前IP
	 * @param ipWhiteConfig
	 *            白名单规则
	 * @return 是否在白名单中
	 */
	public static boolean checkLoginIP(final String ip, final String ipWhiteConfig) {
		if (StringUtils.isEmpty(ip) || StringUtils.isEmpty(ipWhiteConfig)) {
			return false;
		}
		// ip格式不对
		if (!IPUtil.validate(ip)) {
			return false;
		}
		if (IPUtil.DEFAULT_ALLOW_ALL_FLAG.equals(ipWhiteConfig)) {
			return true;
		}
		if (IPUtil.DEFAULT_DENY_ALL_FLAG.equals(ipWhiteConfig)) {
			return false;
		}
		final Set<String> ipList = IPUtil.getAvaliIpList(ipWhiteConfig);
		return IPUtil.checkLoginIP(ip, ipList);
	}

	public static void main(final String[] args) {

		final String ipWhite = "192.168.1.1;" + //设置单个IP的白名单
				"192.168.2.*;" + //设置ip通配符,对一个ip段进行匹配
				"192.168.3.17-192.168.3.38"; //设置一个IP范围
		final boolean flag = IPUtil.checkLoginIP("192.168.2.2", ipWhite);
		final boolean flag2 = IPUtil.checkLoginIP("192.168.1.2", ipWhite);
		final boolean flag3 = IPUtil.checkLoginIP("192.168.3.16", ipWhite);
		final boolean flag4 = IPUtil.checkLoginIP("192.168.3.17", ipWhite);
		System.out.println(flag); //true
		System.out.println(flag2); //false
		System.out.println(flag3); //false
		System.out.println(flag4); //true

		System.out.println(IPUtil.getAvaliIpList(ipWhite));
		System.out.println(IPUtil.getIpByAllowIp(ipWhite));

	}

}